﻿/// <reference path="~/Scripts/FlowBasis/FlowBasis-all-vsdoc.js" />

FlowBasis.defineNamespace("UI");

FlowBasis.UI.JsonForm = function (options) {
    var self = this;

    this.element = jQuery(options.container);
    var actualElement = this.element.get(0);
    actualElement.__jsonForm = this;

    // Deserialize json settings from data-json-form if applicable.
    var formOptionsJson = this.element.attr("data-json-form");
    if (formOptionsJson) {
        var formOptions = JSON.parse(formOptionsJson);
        jQuery.extend(true, options, formOptions);
    }

    if (options.formName) {
        this.formName = options.formName;
    }

    if (options.associatedForms) {        
        var associatedForms = [];
        
        jQuery(options.associatedForms).each(function (index, formEntry) {
            var form = FlowBasis.UI.JsonForm.getJsonForm(formEntry);
            if (form) {
                associatedForms.push(form);
            }
        });

        this.associatedForms = associatedForms;
    }
    else {
        this.associatedForms = [];
    }

    this._afterInputChangedHandler = function () {
        self._afterInputChanged();
    };

    // Register change handlers for input elements.
    var inputElements = jQuery("input", this.element).add("select", this.element);
    inputElements.keyup(self._afterInputChangedHandler);
    inputElements.change(self._afterInputChangedHandler);

    // Register for change notifications on associated forms.
    jQuery(this.associatedForms).each(function (index, form) {
        jQuery(form).bind("inputDataChanged", self._afterInputChangedHandler);
    });
};


FlowBasis.UI.JsonForm.getJsonForm = function (containerOrObject) {    
    if (_.isString(containerOrObject) || _.isElement(containerOrObject)) {
        var element = jQuery(containerOrObject);
        var item = element.get(0);
        if (item.__jsonForm) {
            return item.__jsonForm;
        }
        else {
            var form = new FlowBasis.UI.JsonForm({ container: element });
            return form;
        }
    }
    else {
        throw "Unsupported form entry for container.";
    }
};

FlowBasis.UI.JsonForm.prototype.getInputData = function () {

    var inputData = {};

    jQuery(this.associatedForms).each(function (index, form) {
        var formInputData = form.getInputData();
        if (formInputData) {
            if (form.formName && formInputData) {
                inputData[form.formName] = formInputData;
            }
            else {
                jQuery.extend(true, inputData, formInputData);
            }
        }        
    });

    this._recursiveGetInputData(this.element, inputData);

    return inputData;
};

FlowBasis.UI.JsonForm.prototype._recursiveGetInputData = function (element, inputDataSoFar) {
    var self = this;

    jQuery(element).children().each(function (index, item) {
        var jItem = jQuery(item);

        if (self._isChildJsonForm(jItem)) {
            var childJsonForm = self._getChildJsonForm(jItem);
            var childInputData = childJsonForm.getInputData();
            if (childJsonForm.formName)
            {
                inputDataSoFar[childJsonForm.formName] = childInputData;
            }
            else
            {
                // TODO: merge settings into top-level.
                throw "Child json form without formName is not supported yet.";
            }
        }
        else {
            var name = jItem.attr("data-json-input-name");
            if (name) {
                var inputValue = self._getElementJsonInputValue(jItem);
                if (typeof(inputValue) != "undefined") {
                    inputDataSoFar[name] = inputValue;
                }
            }

            self._recursiveGetInputData(jItem, inputDataSoFar);
        }        
    });
};


FlowBasis.UI.JsonForm.prototype._getElementJsonInputValue = function (element) {
    var item = element.get(0);
    if (item.nodeName == "INPUT") {
        var inputType = element.attr("type");
        if (inputType) {
            inputType = inputType.toLowerCase();
            if (inputType == "text" || inputType == "hidden") {                                        
                var value = element.val();

                var valueDataType = element.attr("data-json-input-type");
                if (valueDataType) {
                    if (valueDataType == "number") {
                        if (value !== null && typeof value != "undefined") {
                            value = parseFloat(value);
                        }
                    }
                }

                return value;                    
            }
            else if (inputType == "checkbox") {                
                var value = element.is(":checked");
                return value;                
            }
            else if (inputType == "radio") {                          
                if (element.is(":checked")) {
                    var value = element.val();
                    return value;                
                }
            }
        }        
    }
    else if (item.nodeName == "SELECT") {
        return element.val();
    }
};


FlowBasis.UI.JsonForm.prototype._isChildJsonForm = function (element) {
    if (element.get(0).__jsonForm || element.attr("data-json-form")) {
        return true;
    }
    else {
        return false;
    }
};

FlowBasis.UI.JsonForm.prototype._getChildJsonForm = function (element) {
    if (element.get(0).__jsonForm) {        
        return element.get(0).__jsonForm;
    }
    else {        
        return new FlowBasis.UI.JsonForm({ container: element });
    }
};



FlowBasis.UI.JsonForm.prototype._afterInputChanged = function () {
    // TODO: Check to see if there was an actual change from previous input data before triggering change handler with deepCompare.

    jQuery(this).trigger("inputDataChanged");
};